﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;


/// <summary>
/// 用于动态创建方法的工具。
/// </summary>
public sealed class MethodBuilder : MemberBuilder {

    /// <summary>
    /// 表示一个函数参数。
    /// </summary>
    public sealed class Parameter : SingleLinkedListNode {

        public enum ParameterAttributes : byte {

            /// <summary>
            /// 表示这是一个输入参数。
            /// </summary>
            @in = 0,

            /// <summary>
            /// 表示这是一个输出参数。
            /// </summary>
            @out = 1,

            /// <summary>
            /// 表示这是一个输入输出参数。
            /// </summary>
            @ref = 2,

            /// <summary>
            /// 表示这是一个变长参数。
            /// </summary>
            @params = 3,

            /// <summary>
            /// 表示这是一个可变参数。
            /// </summary>
            @var = 4,

            /// <summary>
            /// 表示这是一个可选参数。
            /// </summary>
            optional = 5,

            unicodeName = 1 << 4,

            linkedName = 1 << 5,

            hasDefaultValue = 1 << 6,
        }

        public ParameterAttributes attributes;

        public TypeBuilder type;

        public string name;

        /// <summary>
        /// 对于可选参数，存储当前参数的默认值。
        /// </summary>
        public ByteArrayList value;

    }

    /// <summary>
    /// 获取或设置当前方法的返回值类型。
    /// </summary>
    public TypeBuilder returnType;

    public SingleLinkedList<Parameter> parameters;

    /// <summary>
    /// 获取或设置当前方法实现的接口类型。
    /// </summary>
    public TypeBuilder implimentType;

    /// <summary>
    /// 返回用于生成当前函数主体的指令构建器。
    /// </summary>
    public IRBuilder body;

    public override void write(WriteContext context) {
        attributes |= MemberAttributes.method;
        if (implimentType != null) {
            attributes |= MemberAttributes.hasImplementedType;
        }
        if (body == null) {
            attributes |= MemberAttributes.empty;
        }
        base.write(context);
        Debug.Assert(returnType != null);
        context.writeMember(returnType);

        // 写入参数。
        int parameterCount = parameters.length;
        Debug.Assert(parameterCount <= byte.MaxValue);
        context.writeByte((byte)parameterCount);
        if (parameterCount > 0) {
            foreach (var parameter in parameters) {
                bool nameIsUnicode = Util.isUnicode(parameter.name);
                if(nameIsUnicode) {
                    parameter.attributes |= Parameter.ParameterAttributes.unicodeName;
                }
                uint nameOffset;
                if (parameter.name.Length <= (nameIsUnicode ? 1 : 3)) {
                    nameOffset = 0;
                } else {
                    nameOffset = context.getStringOffset(parameter.name);
                    if(nameOffset > 0) {
                        parameter.attributes |= Parameter.ParameterAttributes.linkedName;
                    } else {
                        Debug.Assert(parameter.name.Length <= byte.MaxValue);
                        context.setStringOffset(parameter.name, (uint)context.target.Position + 5);// 跳过 参数属性和类型。
                    }
                }

                if (parameter.value != null) {
                    parameter.attributes |= Parameter.ParameterAttributes.hasDefaultValue;
                }

                context.writeByte((byte)parameter.attributes);
                context.writeMember(parameter.type);

                if(nameOffset > 0) {
                    context.writeInt(nameOffset);
                } else {
                    context.writeByte((byte)parameter.name.Length);
                    context.writeString(parameter.name, nameIsUnicode);
                }

                if (parameter.value != null) {
                    context.writeByteArrayList(parameter.value);
                }

            }
        }

        if (body != null) {
            context.writeByteArrayList(body.output_bak);
        }
    }

}

